package com.fly.snailrun.base.web;

import com.fly.snailrun.base.exception.BusinessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.client.RestClientException;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import java.util.ArrayList;
import java.util.List;

/**
 * @author:gaoxu
 * @create:2020-04-01 10:38
 **/
@ControllerAdvice
public class GlobalExceptionHandler {

    private static Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    @ExceptionHandler(Exception.class)
    public ResponseVo handleException(Exception exception) {
        String msg = exception.getClass().getSimpleName() + ":" + exception.getMessage();
        ResponseVo responseVo;
        if (isRequestParameterException(exception)) {
            log.error(msg, exception);
            responseVo = new ResponseVo(CommonErrorCode.VALIDATE_ERROR.getErrorCode(), CommonErrorCode.VALIDATE_ERROR.getMemo());
        } else {
            log.error(msg, exception);
            responseVo = new ResponseVo(CommonErrorCode.APPLICATION_OPER_ERROR.getErrorCode(), CommonErrorCode.APPLICATION_OPER_ERROR.getMemo());
        }
        return responseVo;
    }


    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    @ExceptionHandler(BusinessException.class)
    public ResponseVo BusinessExceptionException(BusinessException e) {
        String msg = e.getClass().getSimpleName() + ":" + e.getMessage();
        log.error(msg, e);
        return ResponseVo.creComErrorResult(e.getErrCode() + ":" + e.getMessage());
    }


    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseVo handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        BindingResult br = e.getBindingResult();
        if (br.hasFieldErrors()) {
            List<FieldError> fieldErrorList = br.getFieldErrors();
            List<String> errors = new ArrayList<>(fieldErrorList.size());
            for (FieldError error : fieldErrorList) {
                errors.add(error.getField() + ":" + error.getDefaultMessage());
            }
            return new ResponseVo(CommonErrorCode.VALIDATE_ERROR.getErrorCode(), errors.toString());
        }
        return new ResponseVo(CommonErrorCode.VALIDATE_ERROR.getErrorCode(), CommonErrorCode.VALIDATE_ERROR.getMemo());
    }

    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    @ExceptionHandler(value = RestClientException.class)
    public ResponseVo restClientExceptionHandler(RestClientException exception) {
        log.error("调用三方接口出错, exception:{}", exception);
        ResponseVo responseVo = new ResponseVo(CommonErrorCode.APPLICATION_OPER_ERROR.getErrorCode(), CommonErrorCode.APPLICATION_OPER_ERROR.getMemo());
        return responseVo;
    }

    private boolean isRequestParameterException(Exception exception) {
        return exception instanceof HttpMessageNotReadableException ||
                exception instanceof MissingServletRequestParameterException ||
                exception instanceof HttpRequestMethodNotSupportedException ||
                exception instanceof MethodArgumentTypeMismatchException
                ;
    }
}